﻿using Ribbon.Core.Event;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Ribbon.Core
{ 
    internal class PopupWindow : ToolStripDropDown
    {
        public event ColorChangedDelegate ColorChanged;

        private ToolStripControlHost host;

        private ColorPopup content;

        public Color SelectedColor
        {
            get { return content.SelectedColor; }
            set { content.SelectedColor = value; }
        }

        public PopupWindow(ColorPopup content)
        {
            if (content == null)
                throw new ArgumentNullException("content");

            this.content = content;
            this.AutoSize = false;
            this.DoubleBuffered = true;
            this.ResizeRedraw = true;
            //create a host that will host the content
            host = new ToolStripControlHost(content);

            this.Padding = Margin = host.Padding = host.Margin = Padding.Empty;
            this.MinimumSize = content.MinimumSize;
            content.MinimumSize = content.Size;
            MaximumSize = new Size(content.Size.Width + 1, content.Size.Height + 1);
            content.MaximumSize = new Size(content.Size.Width + 1, content.Size.Height + 1);
            Size = new Size(content.Size.Width + 1, content.Size.Height + 1);

            content.Location = Point.Empty;
            //add the host to the list
            Items.Add(host);
        }

        protected override void OnClosed(ToolStripDropDownClosedEventArgs e)
        {
            //when the window close tell the parent that the color changed
            if (ColorChanged != null)
                ColorChanged(this, new ColorEventArgs(this.SelectedColor));
        }
    }

    ///<summary>
    ///this class represends the control that has all the color radio buttons.
    ///this control gets embedded into the PopupWindow class.
    ///</summary>
    internal class ColorPopup : UserControl
    {
        //private Color[] colors = { Color.Black, Color.Gray, Color.Maroon, Color.Olive, Color.Green, Color.Teal, Color.Navy, Color.Purple, Color.White, Color.Silver, Color.Red, Color.Yellow, Color.Lime, Color.Aqua, Color.Blue, Color.Fuchsia };
        private Color[] colors = {
                Color.Black, Color.Navy, Color.DarkGreen, Color.DarkCyan, Color.DarkRed, Color.DarkMagenta, Color.Olive,
                Color.LightGray, Color.DarkGray, Color.Blue, Color.Lime, Color.Cyan, Color.Red, Color.Fuchsia, 
                Color.Yellow, Color.White, Color.RoyalBlue, Color.MediumBlue,  Color.LightGreen, Color.MediumSpringGreen, Color.Chocolate,
                Color.Pink, Color.Khaki, Color.WhiteSmoke, Color.BlueViolet, Color.DeepSkyBlue, Color.OliveDrab, Color.SteelBlue,
                Color.DarkOrange, Color.Tomato, Color.HotPink, Color.DimGray,Color.FromArgb (238,238,242),
            };

        private string[] colorNames = {
                "黑色", "藏青", "深绿", "深青", "红褐", "洋红", "褐绿", 
                "浅灰", "灰色", "蓝色", "绿色", "青色", "红色", "紫红", 
                "黄色", "白色", "蓝灰", "藏蓝", "淡绿", "青绿", "黄褐", 
                "粉红", "嫩黄", "银白", "紫色", "天蓝", "灰绿", "青蓝", 
                "橙黄", "桃红", "英红", "深灰", "浅灰"
            };

        private ToolTip toolTip = new ToolTip();
        private ColorRadioButton[] buttons;
        private Button moreColorsBtn;
        private Color selectedColor = Color.Blue;

        ///<summary>
        ///get or set the selected color
        ///</summary>
        public Color SelectedColor
        {
            get { return selectedColor; }
            set
            {
                selectedColor = value;
                Color[] colors = this.colors;
                for (int i = 0; i < colors.Length; i++)
                    buttons[i].Checked = selectedColor == colors[i];
            }
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            this.Name = "Color Popup";
            this.Text = string.Empty;
            this.ResumeLayout(false);
        }

        public ColorPopup()
        {
            InitializeComponent();

            SetupButtons();

            this.Paint += new PaintEventHandler(OnPaintBorder);
        }

        //place the buttons on the window.
        private void SetupButtons()
        {
            Controls.Clear();

            int x = 1;
            int y = 2;
            int breakCount = 7;
            Color[] colors = this.colors;
            this.buttons = new ColorRadioButton[colors.Length];
            this.ClientSize = new Size(139, 137);
            //color buttons
            for (int i = 0; i < colors.Length; i++)
            {
                if (i > 0 && i % breakCount == 0)
                {
                    y += 19;
                    x = 1;
                }
                buttons[i] = new ColorRadioButton(colors[i], this.BackColor);
                buttons[i].Location = new Point(x, y);
                toolTip.SetToolTip(buttons[i], colorNames[i]);
                Controls.Add(buttons[i]);
                buttons[i].Click += new EventHandler(BtnClicked);
                if (selectedColor == colors[i])
                    buttons[i].Checked = true;
                x += 19;
            }

            //line...
            y += 24;
            var label = new Label();
            label.AutoSize = false;
            label.Text = string.Empty;
            label.Width = this.Width - 5;
            label.Height = 2;
            label.BorderStyle = BorderStyle.Fixed3D;
            label.Location = new Point(4, y);
            Controls.Add(label);

            //button
            y += 7;
            moreColorsBtn = new Button();
            moreColorsBtn.FlatStyle = FlatStyle.Popup;
            moreColorsBtn.Text = "其它颜色...";
            moreColorsBtn.Location = new Point(6, y);
            moreColorsBtn.ClientSize = new Size(127, 23);
            moreColorsBtn.Click += new EventHandler(OnMoreClicked);
            Controls.Add(moreColorsBtn);
        }

        private void OnPaintBorder(object sender, PaintEventArgs e)
        {
            var rect = this.ClientRectangle;
            rect.Width -= 1;
            rect.Height -= 1;
            e.Graphics.DrawRectangle(new Pen(SystemColors.WindowFrame), rect);
        }

        public void BtnClicked(object sender, EventArgs e)
        {
            selectedColor = ((ColorRadioButton)sender).ForeColor;
            ((ToolStripDropDown)Parent).Close();
        }

        public void OnMoreClicked(object sender, EventArgs e)
        {
            ((ToolStripDropDown)Parent).Close();

            var pt = this.PointToScreen(this.Location);
            var dlg = new ColorPicker(pt.X - 2, pt.Y);
            dlg.Color = SelectedColor;
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                selectedColor = dlg.Color;

                if (OnPickColor != null)
                {
                    OnPickColor(null, new ColorEventArgs(selectedColor));
                }
            }
        }

        public event ColorChangedDelegate OnPickColor;
    }


    /// <summary>
    /// a button style radio button that shows a color
    /// </summary>
    internal class ColorRadioButton : RadioButton
    {
        public ColorRadioButton(Color color, Color backColor)
        {
            this.ClientSize = new Size(21, 21);
            this.Appearance = Appearance.Button;
            this.Name = "button";
            this.Visible = true;
            this.ForeColor = color;
            this.FlatAppearance.BorderColor = backColor;
            this.FlatAppearance.BorderSize = 0;
            this.FlatStyle = FlatStyle.Flat;
            this.Paint += new PaintEventHandler(OnPaintButton);
        }

        private void OnPaintButton(object sender, PaintEventArgs e)
        {
            //paint a square on the face of the button using the controls foreground color
            Rectangle colorRect = new Rectangle(ClientRectangle.Left + 5, ClientRectangle.Top + 5, ClientRectangle.Width - 9, ClientRectangle.Height - 9);
            e.Graphics.FillRectangle(new SolidBrush(this.ForeColor), colorRect);
            e.Graphics.DrawRectangle(Pens.DarkGray, colorRect);
        }
    }

    //修正颜色框弹出位置
    public class ColorPicker : ColorDialog
    {
        private const Int32 WM_INITDIALOG = 0x0110;
        private const uint SWP_NOSIZE = 0x0001;
        private const uint SWP_SHOWWINDOW = 0x0040;
        private const uint SWP_NOZORDER = 0x0004;
        private const uint UFLAGS = SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW;
        private static readonly IntPtr HWND_TOP = new IntPtr(0);

        private int x;
        private int y;
        private string title = null;

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool SetWindowText(IntPtr hWnd, string text);
        [DllImport("user32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        public ColorPicker(int x, int y, String title = null)
        {
            this.x = x;
            this.y = y;
            this.title = title;
        }

        protected override IntPtr HookProc(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
        {
            IntPtr hookProc = base.HookProc(hWnd, msg, wparam, lparam);
            if (msg == WM_INITDIALOG)
            {
                if (!string.IsNullOrEmpty(this.title))
                    SetWindowText(hWnd, this.title);
                var r = new RECT();
                GetWindowRect(hWnd, ref r);
                int width = r.Right - r.Left;
                int height = r.Bottom - r.Top;
                var wa = Screen.PrimaryScreen.WorkingArea;
                int sw = wa.Width;
                int sh = wa.Height;
                if (this.x > sw - width)
                    this.x = sw - width;
                if (y > sh - height)
                    y = sh - height;
                SetWindowPos(hWnd, HWND_TOP, this.x, this.y, 0, 0, UFLAGS);
            }
            return hookProc;
        }
    }
}
